home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / dev / sun4.md / devVMElink.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  41KB  |  1,357 lines

  1. /* 
  2.  * devVMElink.c --
  3.  *
  4.  *    Routines used for running the Bit-3 VME-VME card cage link
  5.  *    board set.  These routines are to set up and handle a master
  6.  *    board; a slave interface should require no (software) setup.
  7.  *
  8.  * Copyright 1990 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/dev/sun4.md/devVMElink.c,v 1.7 92/10/23 15:04:40 elm Exp $ SPRITE (Berkeley)";
  20. #endif /* not lint */
  21.  
  22. #include "sprite.h"
  23. #include "stdio.h"
  24. #include "mach.h"
  25. #include "dev.h"
  26. #include "devInt.h"
  27. #include "stdlib.h"
  28. #include "sync.h"
  29. #include "vmMach.h"
  30. #include "devVMElink.h"
  31. #include "string.h"
  32.  
  33. #include "dbg.h"
  34.  
  35. /*
  36.  * Uncomment the following line of code to use the kernel call
  37.  * VmMach_MapInBigDevice.  Currently, this call doesn't work.
  38.  */
  39.  
  40. #define MAP_IN_BIG_DEVICE
  41.  
  42.  
  43. static VMELinkInfo *VMEInfo[DEV_VMELINK_MAX_BOARDS];
  44. static Boolean devVMElinkInitted = FALSE;
  45.  
  46. static int devVMElinkDebug = FALSE;
  47.  
  48. typedef void (*VoidFunc)();
  49. typedef unsigned short uint16;
  50.  
  51. void    DevVMElinkDmaDone    _ARGS_((VMELinkInfo* linkInfo));
  52. Boolean DevVMElinkXferData    _ARGS_((VMELinkInfo* linkInfo));
  53.  
  54. /*
  55.  * These are the addresses for each card's "window" register access.
  56.  */
  57. unsigned int windowPhysAddr[] = {0xd0010000, 0xd0030000, 0xff810000,
  58. #if 0
  59.                  0xd0050000, 0xd0070000, 0xd0090000,
  60.                  0xd00b0000, 0xd00d0000, 0xd00f0000,
  61.                  0xd0110000, 0xd0130000, 0xd0150000,
  62. #else
  63.                  0, 0, 0,
  64.                  0, 0, 0,
  65.                  0, 0, 0,
  66. #endif
  67. };
  68.  
  69.  
  70. /*
  71.  *----------------------------------------------------------------------
  72.  *
  73.  * DevVMElinkReset
  74.  *
  75.  *    Reset the VME link board.  Also set up any necessary registers
  76.  *    with the proper values.  If a hard reset is requested, or if
  77.  *    the remote board is wedged, the remote card cage will be
  78.  *    reset (VME SYSRESET).
  79.  *
  80.  * Returns:
  81.  *    SUCCESS if reset worked, error code otherwise.
  82.  *
  83.  * Side effects:
  84.  *    Resets the VME link board.  Any currently-running operation is
  85.  *    aborted.
  86.  *
  87.  *----------------------------------------------------------------------
  88.  */
  89. ReturnStatus
  90. DevVMElinkReset (linkInfo, hardReset)
  91. VMELinkInfo *linkInfo;
  92. int hardReset;
  93. {
  94.     unsigned char curStatus = DEV_VMELINK_REMOTE_DOWN;
  95.     unsigned char remoteStatus;
  96.     ReturnStatus status = SUCCESS;
  97.     CtrlRegs *regPtr = linkInfo->regArea;
  98.  
  99.     MASTER_LOCK (&linkInfo->mutex);
  100.  
  101.     if (devVMElinkDebug) {
  102.     printf ("DevVMElinkReset: starting reset.\n");
  103.     }
  104.  
  105.     /*
  106.      * Clear all state except vme address space state bit and whether or
  107.      * not the link has memory mapped in.
  108.      */
  109.     linkInfo->state &= (DEV_VMELINK_STATE_VME_A32 | DEV_VMELINK_STATE_NO_MAP);
  110.     linkInfo->position = 0;
  111.     status = Mach_Probe (sizeof (curStatus), (char *)&(regPtr->LocalStatus),
  112.              (char *)&curStatus);
  113.     if (devVMElinkDebug) {
  114.     printf ("DevVMElinkReset: Status was 0x%x\n", curStatus);
  115.     }
  116.     if (status != SUCCESS) {
  117.     printf("DevVMElinkReset: local board not responding.\n");
  118.     goto resetExit;
  119.     }
  120.  
  121.     if (!(curStatus & DEV_VMELINK_REMOTE_DOWN)) {
  122.     /*
  123.      * Try to read the remote status register.  If we can't do it,
  124.      * reset the remote card cage whether or not it was requested.
  125.      */
  126.     if (Mach_Probe (sizeof (remoteStatus), (char *)&(regPtr->RemoteCmd1),
  127.             (char *)&remoteStatus) != SUCCESS) {
  128.         hardReset = TRUE;
  129.     }
  130.     /*
  131.      * Reset the remote card cage if requested or needed.
  132.      */
  133.     if (hardReset) {
  134.         printf ("DevVMElinkReset: Resetting remote VME link card...\n");
  135.         regPtr->RemoteCmd1 = DEV_VMELINK_REMOTE_RESET;
  136.         if (devVMElinkDebug) {
  137.         printf ("DevVMElinkReset: Just reset remote board.\n");
  138.         }
  139.         MACH_DELAY(1000000);
  140.     }
  141.     remoteStatus = regPtr->RemoteCmd1;
  142.     } else {
  143.     printf ("DevVMElinkReset: Remote VME link down; can't access.\n");
  144.     }
  145.  
  146.     regPtr->LocalCmd = DEV_VMELINK_CLEAR_LOCAL_ERRS;
  147.  
  148.     curStatus = regPtr->LocalStatus;
  149.     if (devVMElinkDebug) {
  150.     printf ("DevVMElinkReset: Status is now 0x%x (after errs cleared)\n",
  151.         curStatus);
  152.     }
  153.     regPtr->LocalIntrVec = (unsigned char)linkInfo->vectorNumber;
  154.  
  155.   resetExit:
  156.     if (devVMElinkDebug) {
  157.     printf ("Just before putting in local flags, status is 0x%x\n",
  158.         regPtr->LocalStatus);
  159.     }
  160.     linkInfo->LocalFlags = 0;
  161.     regPtr->LocalCmd = linkInfo->LocalFlags;
  162.     linkInfo->RemoteFlags1 = 0;
  163.     linkInfo->RemoteFlags2 = 0 /*DEV_VMELINK_REMOTE_PAUSE_16*/;
  164.     if (!(curStatus & DEV_VMELINK_REMOTE_DOWN)) {
  165.     if (devVMElinkDebug) {
  166.         printf ("Just before putting in remote flags, status is 0x%x\n",
  167.             regPtr->LocalStatus);
  168.     }
  169.     regPtr->RemoteCmd1 = linkInfo->RemoteFlags1;
  170.     regPtr->RemoteCmd2 = linkInfo->RemoteFlags2;
  171.     } else {
  172.     if (devVMElinkDebug) {
  173.         printf ("DevVMElinkReset: remote down; not initted cmd regs\n");
  174.     }
  175.     }
  176.     MASTER_UNLOCK (&linkInfo->mutex);
  177.     return(status);
  178. }
  179.  
  180. /***********************************************************************
  181.  *
  182.  * DevVMElinkAttach
  183.  *
  184.  *    Attach a VME link board as a block device.
  185.  *
  186.  * Returns: block device handle
  187.  *
  188.  ***********************************************************************
  189.  */
  190. DevBlockDeviceHandle *
  191. DevVMElinkAttach (devPtr)
  192. Fs_Device *devPtr;
  193. {
  194.     DevVMElinkHandle *handlePtr;
  195.     VMELinkInfo *linkInfo;
  196.  
  197.     if (devPtr->unit >= DEV_VMELINK_MAX_BOARDS ||
  198.     ((devPtr->data = (ClientData)(VMEInfo[devPtr->unit])) == NULL)) {
  199.     return ((DevBlockDeviceHandle *)NIL);
  200.     }
  201.  
  202.     linkInfo = (VMELinkInfo *)(devPtr->data);
  203.     handlePtr = (DevVMElinkHandle *) malloc (sizeof (DevVMElinkHandle));
  204.     if (handlePtr == NULL) {
  205.     return ((DevBlockDeviceHandle *)NIL);
  206.     }
  207.     handlePtr->blockHandle.blockIOProc = DevVMElinkBlockIO;
  208.     handlePtr->blockHandle.IOControlProc = DevVMElinkBlockIOControl;
  209.     handlePtr->blockHandle.releaseProc = DevVMElinkRelease;
  210.     handlePtr->blockHandle.minTransferUnit = sizeof (int);
  211.     handlePtr->blockHandle.maxTransferSize = DEV_VMELINK_MAX_TRANSFER_SIZE;
  212.     handlePtr->linkInfo = linkInfo;
  213.     handlePtr->magic = DEV_VMELINK_HANDLE_MAGIC;
  214.     MASTER_LOCK (&(linkInfo->mutex));
  215.     linkInfo->numAttached += 1;
  216.     MASTER_UNLOCK (&(linkInfo->mutex));
  217.     return ((DevBlockDeviceHandle *)handlePtr);
  218. }
  219.  
  220. /***********************************************************************
  221.  *
  222.  * DevVMElinkRelease
  223.  *
  224.  *    Release the resources used by an attach().  Currently, this
  225.  *    means decrementing the count of attachers.
  226.  *
  227.  ***********************************************************************
  228.  */
  229. ReturnStatus
  230. DevVMElinkRelease (devHandle)
  231. DevVMElinkHandle *devHandle;
  232. {
  233.     VMELinkInfo *linkInfo;
  234.  
  235.     if (devHandle->magic != DEV_VMELINK_HANDLE_MAGIC) {
  236.     printf ("DevVMElinkRelease: bad handle magic #: 0x%x\n",
  237.         devHandle->magic);
  238.     return (FAILURE);
  239.     }
  240.     linkInfo = devHandle->linkInfo;
  241.     MASTER_LOCK (&(linkInfo->mutex));
  242.     linkInfo->numAttached -= 1;
  243.     MASTER_UNLOCK (&(linkInfo->mutex));
  244.     free ((char *)devHandle);
  245.  
  246.     return (SUCCESS);
  247. }
  248.  
  249. /***********************************************************************
  250.  *
  251.  * DevVMElinkBlockIO
  252.  *
  253.  *    This routine copies all the information into a VME transfer
  254.  *    request block.  It then queues up the I/O by calling DevQueue.
  255.  *
  256.  * Returns: standard Sprite return status
  257.  *
  258.  * Side effects: Queues up a request for a VME transfer
  259.  *
  260.  ***********************************************************************
  261.  */
  262. ReturnStatus
  263. DevVMElinkBlockIO (devHandle, devReqPtr)
  264. DevVMElinkHandle *devHandle;
  265. DevBlockDeviceRequest *devReqPtr;
  266. {
  267.     DevVMElinkReq    *req;
  268.     VMELinkInfo*    linkInfo;
  269.  
  270.     req = (DevVMElinkReq *)devReqPtr->ctrlData;
  271.     linkInfo = req->linkInfo = devHandle->linkInfo;
  272.     if (linkInfo->state & DEV_VMELINK_STATE_NO_MAP) {
  273.     return (FAILURE);
  274.     }
  275.     List_InitElement ((List_Links *)&(req->links));
  276.     req->origReq = devReqPtr;
  277.     req->startAddress = devReqPtr->startAddress;
  278.     req->length = devReqPtr->bufferLen;
  279.     req->buffer = devReqPtr->buffer;
  280.     req->operation = devReqPtr->operation;
  281.     req->status = SUCCESS;
  282.  
  283.     MASTER_LOCK (&linkInfo->mutex);
  284.     List_Insert ((List_Links*)req, LIST_ATREAR (&linkInfo->reqHdr));
  285.     if (!(linkInfo->state & DEV_VMELINK_STATE_DMA_IN_USE)) {
  286.     DevVMElinkXferData (linkInfo);
  287.     }
  288.     MASTER_UNLOCK (&linkInfo->mutex);
  289.     return (SUCCESS);
  290. }
  291.  
  292. /***********************************************************************
  293.  *
  294.  * DevVMElinkDmaDone
  295.  *
  296.  * Side effects:
  297.  *    Copies data over the VME link.  May affect the device queues by
  298.  *    servicing the next request.
  299.  *
  300.  ***********************************************************************
  301.  */
  302. void
  303. DevVMElinkDmaDone (linkInfo)
  304. VMELinkInfo*    linkInfo;
  305. {
  306.     register DevVMElinkReq*    reqPtr;
  307.  
  308.     MASTER_LOCK (&linkInfo->mutex);
  309.     reqPtr = (DevVMElinkReq*)List_First (&linkInfo->reqHdr);
  310.     List_Remove ((List_Links*)reqPtr);
  311.     if (reqPtr->dmaSize > 0) {
  312.     VmMach_DMAFree (reqPtr->dmaSize, (Address)(reqPtr->dmaSpace));
  313.     }
  314.     linkInfo->regArea->RemoteCmd2 = linkInfo->RemoteFlags2;
  315.     linkInfo->state &= ~DEV_VMELINK_STATE_DMA_IN_USE;
  316.     /*
  317.      * Check to see if there's another request outstanding.  If there
  318.      * is, start it up.
  319.      */
  320.     if (!List_IsEmpty ((List_Links*)&linkInfo->reqHdr)) {
  321.     DevVMElinkXferData (linkInfo);
  322.     }
  323.     MASTER_UNLOCK (&linkInfo->mutex);
  324.  
  325.     (reqPtr->origReq->doneProc)(reqPtr->origReq, reqPtr->status,
  326.                 reqPtr->length);
  327. }
  328.  
  329. /*
  330.  *----------------------------------------------------------------------
  331.  *
  332.  * DevVMElinkXferData
  333.  *
  334.  *    Transfer data over the VME link.  If there is a small amount
  335.  *    of data, just copy it over word by word.  If the amount is
  336.  *    larger than 256, copy most of it by DMA and the remainder
  337.  *    word by word.  NOTE: the transfer must be word-aligned on
  338.  *    both sides.  If not, the routine returns an error.
  339.  *
  340.  *    Since the link can't be multiplexed, transfers queue up
  341.  *    at the start of this routine.
  342.  *
  343.  *    The master lock for this interface must be held *before* this
  344.  *    routine is called.
  345.  *    
  346.  * Returns:
  347.  *    TRUE if the request was processed; FALSE otherwise.
  348.  *
  349.  * Side effects:
  350.  *    Data is transferred over the VME link boards.
  351.  *
  352.  *----------------------------------------------------------------------
  353.  */
  354. static
  355. Boolean
  356. DevVMElinkXferData (linkInfo)
  357. VMELinkInfo*    linkInfo;
  358. {
  359.     DevVMElinkReq* reqPtr = (DevVMElinkReq*)List_First (&(linkInfo->reqHdr));
  360.     int bufSize;
  361.     unsigned long remoteAddr;
  362.     unsigned long bufAddr;
  363.     unsigned long dmaAddr;
  364.     int dmaSize = 0;
  365.     int copySize;
  366.     unsigned char dmaCmd;
  367.     DmaRegs *dmaPtr = linkInfo->dmaRegs;
  368.     register CtrlRegs*    regPtr = linkInfo->regArea;
  369.  
  370.     linkInfo->curReq = reqPtr;
  371.     bufSize = reqPtr->length;
  372.     if (devVMElinkDebug) {
  373.     printf ("VMElink:  Trying I/O at 0x%x for 0x%x bytes.\n",
  374.         linkInfo->position, bufSize);
  375.     }
  376.     /*
  377.      * First, copy the data that won't be DMAed.
  378.      */
  379.     linkInfo->state |= DEV_VMELINK_STATE_DMA_IN_USE;
  380.     if (bufSize >= linkInfo->minDmaSize) {
  381.     dmaSize = bufSize & DEV_VMELINK_DMA_BUFSIZE_MASK;
  382.     } else {
  383.     dmaSize = 0;
  384.     }    
  385.     copySize = bufSize - dmaSize;
  386.     if (devVMElinkDebug) {
  387.     printf("DevVMElinkXferData: bufsize=0x%x dmaSize=0x%x copySize=0x%x\n",
  388.            bufSize, dmaSize, copySize);
  389.     }
  390.     remoteAddr = (unsigned int)linkInfo->position + dmaSize;
  391.     bufAddr = (unsigned int)(reqPtr->buffer + dmaSize);
  392.     dmaAddr = (unsigned int)(linkInfo->smallMap + (remoteAddr & 0xffff));
  393.     regPtr->RemoteCmd1 = linkInfo->RemoteFlags1 | DEV_VMELINK_USE_PAGE_REG;
  394.     regPtr->RemotePageAddrHigh = ((unsigned int)remoteAddr >> 24) & 0xff;
  395.     regPtr->RemotePageAddrLow =  ((unsigned int)remoteAddr >> 16) & 0xff;
  396.     if (reqPtr->operation == FS_READ) {
  397.     while (copySize > 0) {
  398.         *(int *)bufAddr = *(int *)dmaAddr;
  399.         dmaAddr += 4;
  400.         bufAddr += 4;
  401.         copySize -= 4;
  402.         remoteAddr += 4;
  403.         if (((unsigned int)remoteAddr & 0xffff) == 0) {
  404.         regPtr->RemotePageAddrHigh =
  405.             ((unsigned int)remoteAddr >> 24) & 0xff;
  406.         regPtr->RemotePageAddrLow =
  407.             ((unsigned int)remoteAddr >> 16) & 0xff;
  408.         }
  409.     }
  410.     } else {
  411.     while (copySize > 0) {
  412.         *(int *)dmaAddr = *(int *)bufAddr;
  413.         dmaAddr += 4;
  414.         bufAddr += 4;
  415.         copySize -= 4;
  416.         remoteAddr += 4;
  417.         if (((unsigned int)remoteAddr & 0xffff) == 0) {
  418.         regPtr->RemotePageAddrHigh =
  419.             ((unsigned int)remoteAddr >> 24) & 0xff;
  420.         regPtr->RemotePageAddrLow =
  421.             ((unsigned int)remoteAddr >> 16) & 0xff;
  422.         }
  423.     }
  424.     }
  425.     regPtr->RemoteCmd1 = linkInfo->RemoteFlags1;
  426.  
  427.     if (bufSize >= linkInfo->minDmaSize) {
  428.     /*
  429.      * Map in buffer for DMA, and copy in/out a multiple of
  430.      * 256 bytes.  The remainder will be copied over later.
  431.      */
  432.     bufAddr = (unsigned int)reqPtr->buffer;
  433.     remoteAddr = linkInfo->position;
  434.     dmaAddr = (unsigned int)VmMach_DMAAlloc(dmaSize,(Address)bufAddr);
  435.     if (dmaAddr == 0) {
  436.         panic ("DevVMElinkXferData: couldn't allocate DMA space.\n");
  437.     }
  438.     if (devVMElinkDebug) {
  439.         printf ("DevVMElinkXferData: DMA mapped to 0x%x\n", dmaAddr);
  440.     }
  441.     reqPtr->dmaSpace = (Address)dmaAddr;
  442.     reqPtr->dmaSize = dmaSize;
  443.  
  444.     /*
  445.      * gets user address modifier.
  446.      * requires addr mod 0x3d (for A24) or 0x0d (for A32) on link board
  447.      * Convert dmaAddr to a VME address.
  448.      */
  449.     dmaAddr &= 0x000fffff;
  450.     if (linkInfo->state & DEV_VMELINK_STATE_VME_A32) {
  451.         regPtr->LocalAddrMod = 0x0d;
  452.         if (linkInfo->RemoteFlags2 & DEV_VMELINK_REMOTE_DMA_BLOCK_MODE) {
  453.         regPtr->RemoteAddrMod = 0x0f;
  454.         } else {
  455.         regPtr->RemoteAddrMod = 0x0d;
  456.         }
  457.     } else {
  458.         regPtr->LocalAddrMod = 0x3d;
  459.         if (linkInfo->RemoteFlags2 & DEV_VMELINK_REMOTE_DMA_BLOCK_MODE) {
  460.         regPtr->RemoteAddrMod = 0x3f;
  461.         } else {
  462.         regPtr->RemoteAddrMod = 0x3d;
  463.         }
  464.     }
  465. #if 1
  466.     dmaPtr->localDmaAddr3 = (dmaAddr >> 24) & 0xff;
  467.     dmaPtr->localDmaAddr2 = (dmaAddr >> 16) & 0xff;
  468.     dmaPtr->localDmaAddr1 = (dmaAddr >>  8) & 0xff;
  469.     dmaPtr->localDmaAddr0 = (dmaAddr      ) & 0xff;
  470.     dmaPtr->remoteDmaAddr3 = (remoteAddr >> 24) & 0xff;
  471.     dmaPtr->remoteDmaAddr2 = (remoteAddr >> 16) & 0xff;
  472.     dmaPtr->remoteDmaAddr1 = (remoteAddr >>  8) & 0xff;
  473.     dmaPtr->remoteDmaAddr0 = (remoteAddr      ) & 0xff;
  474.     dmaPtr->dmaLength2 = (dmaSize >> 16) & 0xff;
  475.     dmaPtr->dmaLength1 = (dmaSize >>  8) & 0xff;
  476. #else
  477.     *(uint16*)dmaPtr->localDmaAddr3 = (uint16)((dmaAddr >> 16) & 0xffff);
  478.     *(uint16*)dmaPtr->localDmaAddr1 = (uint16)(dmaAddr & 0xffff);
  479.     *(uint16*)dmaPtr->remoteDmaAddr3 = (uint16)((remoteAddr>>16) & 0xffff);
  480.     *(uint16*)dmaPtr->remoteDmaAddr1 = (uint16)(remoteAddr & 0xffff);
  481.     *(uint16*)dmaPtr->dmaLength2 = (uint16)((dmaSize >> 8) & 0xffff);
  482. #endif
  483.         
  484.     regPtr->LocalCmd = linkInfo->LocalFlags |
  485.         DEV_VMELINK_LOCAL_DISABLE_INT;
  486.     regPtr->RemoteCmd2 = linkInfo->RemoteFlags2 |
  487.         DEV_VMELINK_REMOTE_DISABLE_INT;
  488.     dmaCmd = DEV_VMELINK_DMA_START | DEV_VMELINK_DMA_LONGWORD |
  489.         DEV_VMELINK_DMA_LOCAL_PAUSE | DEV_VMELINK_DMA_ENABLE_INTR
  490.     /* | DEV_VMELINK_DMA_BLOCK_MODE */  ;
  491.     dmaCmd |= (reqPtr->operation == FS_WRITE) ?
  492.         DEV_VMELINK_DMA_LOCAL_TO_REMOTE : DEV_VMELINK_DMA_REMOTE_TO_LOCAL;
  493.     if (devVMElinkDebug) {
  494.         printf ("DevVMElinkXferData: Setting dma cmd for %s to 0x%x\n",
  495.             linkInfo->name, dmaCmd);
  496.     }
  497.     dmaPtr->localDmaCmdReg = dmaCmd;
  498.     /*
  499.      * DevVMElinkDmaDone will be called after the interrupt is taken.
  500.      * It will also check to see if there are more entries waiting in
  501.      * the device queue.
  502.      */
  503.     } else {
  504.     reqPtr->dmaSpace = (Address)NIL;
  505.     reqPtr->dmaSize = 0;
  506.     Proc_CallFunc ((VoidFunc)DevVMElinkDmaDone, (ClientData)linkInfo, 0);
  507.     }
  508.     
  509.     return (TRUE);
  510. }
  511.  
  512. /*----------------------------------------------------------------------
  513.  *
  514.  * DevVMElinkIntr
  515.  *
  516.  *    Called when an interrupt from the link card is received.  This
  517.  *    should only happen when a DMA operation finishes.  Interrupts
  518.  *    from a remote card cage should be handled in the (separate)
  519.  *    device driver for the remote device.
  520.  *
  521.  * Results:
  522.  *    TRUE if this link card caused the interrupt.
  523.  *
  524.  * Side effects:
  525.  *    Notifies any waiting processes, and clears the interrupt bits
  526.  *    on the link card.
  527.  *
  528.  *----------------------------------------------------------------------
  529.  */
  530. Boolean
  531. DevVMElinkIntr (data)
  532. ClientData data;
  533. {
  534.     VMELinkInfo *linkInfo = (VMELinkInfo *)data;
  535.     DmaRegs *dmaRegs;
  536.     CtrlRegs *regPtr;
  537.     Boolean retVal = FALSE;
  538.     unsigned char tmpReg;
  539.  
  540.     dmaRegs = linkInfo->dmaRegs;
  541.     regPtr = linkInfo->regArea;
  542.     MASTER_LOCK (&linkInfo->mutex);
  543.     tmpReg = dmaRegs->localDmaCmdReg;
  544.     if (devVMElinkDebug) {
  545.     printf ("Got intr for %s (dmareg = 0x%x)\n", linkInfo->name, tmpReg);
  546.     }
  547.     if (tmpReg & DEV_VMELINK_DMA_DONE) {
  548.     tmpReg &= ~(DEV_VMELINK_DMA_DONE | DEV_VMELINK_DMA_START);
  549.     dmaRegs->localDmaCmdReg = tmpReg;
  550.     /*
  551.      * Re-enable interrupts.
  552.      */
  553.     regPtr->LocalCmd = linkInfo->LocalFlags;
  554.     regPtr->RemoteCmd2 = linkInfo->RemoteFlags2;
  555.     if (!(linkInfo->state & DEV_VMELINK_STATE_DMA_IN_USE)) {
  556.         if (devVMElinkDebug) {
  557.         printf ("DevVMElinkIntr: DMA finished but shouldn't have\n");
  558.         }
  559.         if (linkInfo->curReq != NULL) {
  560.         linkInfo->curReq->status = FAILURE;
  561.         }
  562.     }
  563.     if (List_IsEmpty (&linkInfo->reqHdr)) {
  564.         panic ("DevVMElinkFinishCopy: no current I/O\n");
  565.     }
  566.     /*
  567.      * Callback DevVMElinkDmaDone to finish the copy and schedule the
  568.      * next one if necessary.
  569.      */
  570.     Proc_CallFunc ((VoidFunc)DevVMElinkDmaDone, (ClientData)linkInfo, 0);
  571.     retVal = TRUE;
  572.     } else if (devVMElinkDebug) {
  573.     printf ("DevVMElinkIntr: bogus interrupt?\n");
  574.     }
  575.     MASTER_UNLOCK (&linkInfo->mutex);
  576.     return (retVal);
  577. }
  578.  
  579. /***********************************************************************
  580.  *
  581.  * setRemotePage
  582.  *
  583.  *    Set the bits which supply the remote page address to those
  584.  *    passed.  Turn on the flag which tells the link board to use
  585.  *    those bits.
  586.  *
  587.  ***********************************************************************
  588.  */
  589. static
  590. void
  591. setRemotePage (linkInfo, pageNum)
  592. register VMELinkInfo    *linkInfo;
  593. unsigned int        pageNum;
  594. {
  595.     register CtrlRegs    *regPtr = linkInfo->regArea;
  596.  
  597.     if (devVMElinkDebug) {
  598.     printf ("Setting remote VME page to 0x%04x\n", pageNum);
  599.     }
  600.     MASTER_LOCK (&linkInfo->mutex);
  601.     linkInfo->RemoteFlags1 |= DEV_VMELINK_USE_PAGE_REG;
  602.     regPtr->RemoteCmd1 = linkInfo->RemoteFlags1;
  603.     regPtr->RemotePageAddrHigh = (unsigned char)((pageNum >> 8) & 0xff);
  604.     regPtr->RemotePageAddrLow = (unsigned char)(pageNum & 0xff);
  605.     linkInfo->state |= DEV_VMELINK_STATE_PAGE_MODE;
  606.     if (devVMElinkDebug) {
  607.     printf ("Page set to 0x%02x%02x; flags are 0x%x\n",
  608.         regPtr->RemotePageAddrHigh, regPtr->RemotePageAddrLow,
  609.         linkInfo->RemoteFlags1);
  610.     }
  611.     MASTER_UNLOCK (&linkInfo->mutex);
  612. }
  613.  
  614. /***********************************************************************
  615.  *
  616.  * turnOffPageMode
  617.  *
  618.  *    Turn off page mode as established using setRemotePage.
  619.  *
  620.  ***********************************************************************
  621.  */
  622. static
  623. void
  624. turnOffPageMode (linkInfo)
  625. register VMELinkInfo    *linkInfo;
  626. {
  627.     MASTER_LOCK (&linkInfo->mutex);
  628.     linkInfo->RemoteFlags1 &= ~DEV_VMELINK_USE_PAGE_REG;
  629.     linkInfo->regArea->RemoteCmd1 = linkInfo->RemoteFlags1;
  630.     linkInfo->state &= ~DEV_VMELINK_STATE_PAGE_MODE;
  631.     MASTER_UNLOCK (&linkInfo->mutex);
  632. }
  633.  
  634. /***********************************************************************
  635.  *
  636.  * setAddrModifier --
  637.  *
  638.  *    Set the address modifier to whatever's passed, and enable its
  639.  *    use on the board.
  640.  *
  641.  * Returns:
  642.  *    none
  643.  * Side effects:
  644.  *    Future VME accesses will use this address modifier.
  645.  *
  646.  ***********************************************************************
  647.  */
  648. static
  649. void
  650. setAddrModifier (linkInfo, mod)
  651. register VMELinkInfo*    linkInfo;
  652. unsigned int        mod;
  653. {
  654.     linkInfo->RemoteFlags2 |= DEV_VMELINK_REMOTE_USE_ADDRMOD;
  655.     linkInfo->regArea->RemoteAddrMod = (unsigned char) mod;
  656.     linkInfo->regArea->RemoteCmd2 = linkInfo->RemoteFlags2;
  657.     if (devVMElinkDebug) {
  658.     printf ("VME address modifier set to 0x%02x\n", mod);
  659.     }
  660. }
  661.  
  662. /***********************************************************************
  663.  *
  664.  * turnOffAddrModifier --
  665.  *
  666.  *    Turn off the remote address modifier.
  667.  *
  668.  * Returns:
  669.  *    none
  670.  * Side Effects:
  671.  *    The address modifier register is no longer used for remote
  672.  *    accesses.
  673.  *
  674.  ***********************************************************************
  675.  */
  676. static
  677. void
  678. turnOffAddrModifier (linkInfo)
  679. register VMELinkInfo*    linkInfo;
  680. {
  681.     linkInfo->RemoteFlags2 &= ~DEV_VMELINK_REMOTE_USE_ADDRMOD;
  682.     linkInfo->regArea->RemoteCmd2 = linkInfo->RemoteFlags2;
  683. }
  684.  
  685. /***********************************************************************
  686.  *
  687.  * DevVMElinkAccessRemoteMemory --
  688.  *
  689.  *    Access memory across the link board.  The accesses are limited
  690.  *    to 4000 bytes, since that's all an ioctl will copy in or out
  691.  *    (with the necessary header).  The bytes must all be consecutive,
  692.  *    and must be long-word sized and aligned.
  693.  *
  694.  ***********************************************************************
  695.  */
  696. ReturnStatus
  697. DevVMElinkAccessRemoteMemory (ioctlPtr, linkInfo)
  698. register Fs_IOCParam *ioctlPtr;
  699. register VMELinkInfo *linkInfo;
  700. {
  701.     int            inSize, outSize;
  702.     int            fmtStatus;
  703.     ReturnStatus    status = SUCCESS;
  704.     DevVMElinkAccessMem    memAccess;
  705.     unsigned int    buf[1000];
  706.     unsigned int    *remote, *local;
  707.     unsigned int    remotePage, remoteOffsetInPage;
  708.     int            nbytes;
  709.  
  710.  
  711.     if (linkInfo->state & DEV_VMELINK_STATE_NO_MAP) {
  712.     status = FAILURE;
  713.     goto accessExit;
  714.     }
  715.     inSize = ioctlPtr->inBufSize;
  716.     outSize = sizeof (memAccess) - sizeof (memAccess.data);
  717.     fmtStatus = Fmt_Convert ("www", ioctlPtr->format, &inSize,
  718.                  ioctlPtr->inBuffer, mach_Format, &outSize,
  719.                  (Address)&memAccess);
  720.     if (fmtStatus != FMT_OK) {
  721.     printf ("DevVMElinkAccessRemoteMemory:cmd format failed, 0x%x\n",
  722.         fmtStatus);
  723.     status = GEN_INVALID_ARG;
  724.     goto accessExit;
  725.     }
  726.     if (memAccess.size > sizeof (buf)) {
  727.     printf ("DevVMElinkAccessRemoteMemory: too much data (0x%x bytes)\n",
  728.         memAccess.size);
  729.     goto accessExit;
  730.     }
  731.  
  732.     if (devVMElinkDebug) {
  733.     printf ("DevVMElinkAccessRemoteMemory: trying 0x%x\n",
  734.         memAccess.destAddress);
  735.     printf ("DevVMElinkAccessRemoteMemory: map at virtual 0x%x\n",
  736.         linkInfo->smallMap);
  737.     }
  738.     remoteOffsetInPage = (((unsigned int)memAccess.destAddress) & 0xffff);
  739.     if ((remoteOffsetInPage & 0x3) != 0) {
  740.     printf ("DevVMElinkAccessRemoteMemory: remote addr (0x%x) unaligned\n",
  741.         memAccess.destAddress);
  742.     goto accessExit;
  743.     }
  744.     remotePage = ((unsigned int)memAccess.destAddress >> 16) & 0xffff;
  745.     remote = (unsigned int *)(linkInfo->smallMap + remoteOffsetInPage);
  746.     setRemotePage (linkInfo, remotePage);
  747.     setAddrModifier (linkInfo, linkInfo->curAddrModifier);
  748.     local = buf;
  749.     if (devVMElinkDebug) {
  750.     printf ("DevVMELinkAccessRemoteMemory: local 0x%x, remote 0x%x\n",
  751.         local, remote);
  752.     printf ("DevVMELinkAccessRemoteMemory: page offset 0x%x\n",
  753.         remoteOffsetInPage);
  754.     }
  755.  
  756.     if (memAccess.direction == DEV_VMELINK_TO_REMOTE) {
  757.     inSize = memAccess.size;
  758.     outSize = sizeof (buf);
  759.     fmtStatus = Fmt_Convert
  760.         ("w*", ioctlPtr->format, &inSize,
  761.          (Address)(((DevVMElinkAccessMem*)(ioctlPtr->inBuffer))->data),
  762.          mach_Format, &outSize, (Address)buf);
  763.     if (fmtStatus != FMT_OK) {
  764.         printf ("DevVMElinkAccessRemoteMemory:data format failed, 0x%x\n",
  765.             fmtStatus);
  766.         status = GEN_INVALID_ARG;
  767.         goto accessExit;
  768.     }
  769.     for (nbytes = 0; nbytes < memAccess.size; nbytes += sizeof (int)) {
  770.         if (linkInfo->state & DEV_VMELINK_STATE_SAFE_COPY) {
  771.         status = Mach_Probe (sizeof (int), (Address)(local++),
  772.                      (Address)(remote++));
  773.         if (status != SUCCESS) {
  774.             if (devVMElinkDebug) {
  775.             printf ("%s: Writing to VME addr 0x%x failed.\n",
  776.                 linkInfo->name, --remote);
  777.             }
  778.             goto accessExit;
  779.         }
  780.         } else {
  781.         *(remote++) = *(local++);
  782.         }
  783.         remoteOffsetInPage += sizeof (int);
  784.         if ((remoteOffsetInPage & 0xffff) == 0) {
  785.         remote = (unsigned int *)linkInfo->smallMap;
  786.         remotePage += 1;
  787.         setRemotePage (linkInfo, remotePage);
  788.         }
  789.     }
  790.     } else if (memAccess.direction == DEV_VMELINK_TO_LOCAL) {
  791.     for (nbytes = 0; nbytes < memAccess.size; nbytes += sizeof (int)) {
  792.         if (linkInfo->state & DEV_VMELINK_STATE_SAFE_COPY) {
  793.         status = Mach_Probe (sizeof (int), (Address)(remote++),
  794.                      (Address)(local++));
  795.         if (status != SUCCESS) {
  796.             if (devVMElinkDebug) {
  797.             printf ("%s: Reading from VME addr 0x%x failed.\n",
  798.                 linkInfo->name, --remote);
  799.             }
  800.             goto accessExit;
  801.         }
  802.         } else {
  803.         *(local++) = *(remote++);
  804.         }
  805.         remoteOffsetInPage += sizeof (int);
  806.         if ((remoteOffsetInPage & 0xffff) == 0) {
  807.         remote = (unsigned int *)linkInfo->smallMap;
  808.         remotePage += 1;
  809.         setRemotePage (linkInfo, remotePage);
  810.         }
  811.     }
  812.     inSize = memAccess.size;
  813.     outSize = ioctlPtr->outBufSize + sizeof (memAccess.data) -
  814.         sizeof (memAccess);
  815.     fmtStatus = Fmt_Convert
  816.         ("w*", mach_Format, &inSize,(Address)buf,ioctlPtr->format,&outSize,
  817.          (Address)(((DevVMElinkAccessMem*)(ioctlPtr->outBuffer))->data));
  818.     if (fmtStatus != FMT_OK) {
  819.         printf ("DevVMElinkAccessRemoteMemory:data format failed, 0x%x\n",
  820.             fmtStatus);
  821.         status = GEN_INVALID_ARG;
  822.         goto accessExit;
  823.     }
  824.     } else {
  825.     printf ("DevVMElinkAccessRemoteMemory: illegal direction 0x%x\n",
  826.         memAccess.direction);
  827.     status = GEN_INVALID_ARG;
  828.     goto accessExit;
  829.     }
  830.  
  831.   accessExit:
  832.     turnOffPageMode (linkInfo);
  833.     turnOffAddrModifier (linkInfo);
  834.  
  835.     return (status);
  836. }
  837.  
  838. /***********************************************************************
  839.  *
  840.  * DevVMElinkBlockIOControl
  841.  *
  842.  *    This is the main IOControl routine for the VMElink driver.
  843.  *    It's easier to fake a "standard" IOControl using the block
  844.  *    driver than vice versa, since the standard IOControl has an
  845.  *    easy way of getting a real handle, but the BlockIOControl
  846.  *    has no way of getting an Fs_Device.
  847.  *
  848.  * Returns: standard Sprite return status
  849.  *
  850.  * Side effects: depends on IOControl
  851.  *
  852.  ***********************************************************************
  853.  */
  854. ENTRY ReturnStatus
  855. DevVMElinkBlockIOControl (handlePtr, ioctlPtr, replyPtr)
  856. DevVMElinkHandle *handlePtr;
  857. register Fs_IOCParam *ioctlPtr;
  858. register Fs_IOReply *replyPtr;
  859.  
  860. /* ARGSUSED */
  861. {
  862.     ReturnStatus status = SUCCESS;
  863.     register volatile CtrlRegs *regPtr;
  864.     register VMELinkInfo *linkData;
  865.     unsigned int passedData;
  866.     DevVMElinkStatus *boardStatus;
  867.     int inSize, outSize;
  868.     int fmtStatus;
  869.  
  870.     if (devVMElinkDebug) {
  871.     printf ("VMElink: doing IOControl 0x%x\n", ioctlPtr->command);
  872.     }
  873.  
  874.     linkData = handlePtr->linkInfo;
  875.     regPtr = linkData->regArea;
  876.  
  877.     /*
  878.      * If the remote board isn't working, don't even bother with the
  879.      * IOcontrol call and just return failure.
  880.      */
  881.     if ((ioctlPtr->command != IOC_VMELINK_DEBUG_ON) &&
  882.     (ioctlPtr->command != IOC_VMELINK_DEBUG_OFF) &&
  883.     (regPtr->RemoteCmd1 & DEV_VMELINK_REMOTE_DOWN)) {
  884.     return (DEV_OFFLINE);
  885.     }
  886.  
  887.     switch (ioctlPtr->command) {
  888.       case IOC_VMELINK_STATUS:
  889.     boardStatus  =(DevVMElinkStatus *)ioctlPtr->inBuffer;
  890.     boardStatus->LocalStatus = (int)regPtr->LocalStatus;
  891.     boardStatus->RemoteStatus = (int)regPtr->RemoteCmd1;
  892.     break;
  893.       case IOC_VMELINK_SET_ADDRMOD:
  894.     passedData = *(unsigned int *)ioctlPtr->inBuffer;
  895.     linkData->curAddrModifier = (unsigned char)passedData;
  896.     break;
  897.       case IOC_VMELINK_SET_MIN_DMA_SIZE:
  898.     outSize = sizeof (linkData->minDmaSize);
  899.     inSize = ioctlPtr->inBufSize;
  900.     fmtStatus = Fmt_Convert ("w", ioctlPtr->format, &inSize,
  901.                  (Address)ioctlPtr->inBuffer, mach_Format,
  902.                  &outSize, (Address)&(linkData->minDmaSize));
  903.     if (fmtStatus != FMT_OK) {
  904.         printf ("Format of VMELINK_SET_MIN_DMA_SIZE failed, 0x%x\n",
  905.             fmtStatus);
  906.         return GEN_INVALID_ARG;
  907.     }
  908.     if (devVMElinkDebug) {
  909.         printf ("VMELINK_SET_MIN_DMA_SIZE: min DMA size set to 0x%x\n",
  910.             linkData->minDmaSize);
  911.     }
  912.     break;
  913. #if 0
  914.       case IOC_VMELINK_NO_ADDRMOD:
  915.     linkData->RemoteFlags2 &= ~DEV_VMELINK_REMOTE_USE_ADDRMOD;
  916.     regPtr->RemoteCmd2 = linkData->RemoteFlags2;
  917.     break;
  918.       case IOC_VMELINK_LOW_VME:
  919.     linkData->addrMsb = 0x00000000;
  920.     break;
  921.       case IOC_VMELINK_HIGH_VME:
  922.     linkData->addrMsb = 0x80000000;
  923.     break;
  924. #endif
  925.  
  926.       case IOC_VMELINK_DEBUG_ON:
  927.     devVMElinkDebug = TRUE;
  928.     break;
  929.       case IOC_VMELINK_DEBUG_OFF:
  930.     devVMElinkDebug = FALSE;
  931.     break;
  932.       case IOC_VMELINK_RESET:
  933.     status = DevVMElinkReset (linkData, TRUE);
  934.     break;
  935.       case IOC_VMELINK_SAFE_COPY_ON:
  936.     linkData->state |= DEV_VMELINK_STATE_SAFE_COPY;
  937.     break;
  938.       case IOC_VMELINK_SAFE_COPY_OFF:
  939.     linkData->state &= ~DEV_VMELINK_STATE_SAFE_COPY;
  940.     break;
  941.       case IOC_VMELINK_REMOTE_BLOCK_MODE_ON:
  942.     linkData->RemoteFlags2 |= DEV_VMELINK_REMOTE_DMA_BLOCK_MODE;
  943.     break;
  944.       case IOC_VMELINK_REMOTE_BLOCK_MODE_OFF:
  945.     linkData->RemoteFlags2 &= ~DEV_VMELINK_REMOTE_DMA_BLOCK_MODE;
  946.     break;
  947.       case IOC_VMELINK_READ_BOARD_STATUS:
  948.     {
  949.         unsigned char    regs[0x20];
  950.         
  951.         regs[0x1] = regPtr->LocalCmd;
  952.         regs[0x3] = regPtr->LocalStatus;
  953.         regs[0x9] = regPtr->RemoteCmd1;
  954.         regs[0x8] = regPtr->RemoteCmd2;
  955.         regs[0x10] = linkData->dmaRegs->localDmaCmdReg;
  956.         
  957.         inSize = sizeof (regs);
  958.         outSize = ioctlPtr->outBufSize;
  959.         fmtStatus = Fmt_Convert ("b32", mach_Format, &inSize,
  960.                      (Address)regs, ioctlPtr->format, &outSize,
  961.                      (Address)ioctlPtr->outBuffer);
  962.         if (fmtStatus != FMT_OK) {
  963.         printf ("Format of VMELINK_READ_BOARD_STATUS failed, 0x%x\n",
  964.             fmtStatus);
  965.         return GEN_INVALID_ARG;
  966.         }
  967.     }
  968.     break;
  969.       case IOC_VMELINK_ACCESS_REMOTE_MEMORY:
  970.     status = DevVMElinkAccessRemoteMemory (ioctlPtr, linkData);
  971.     break;
  972.  
  973.       case IOC_VMELINK_WRITE_REG:
  974.     {
  975.         unsigned char stuff[2];
  976.  
  977.         inSize = ioctlPtr->inBufSize;
  978.         outSize = sizeof (stuff);
  979.         fmtStatus = Fmt_Convert ("b2", ioctlPtr->format, &inSize,
  980.                      (Address)ioctlPtr->inBuffer, mach_Format,
  981.                      &outSize, (Address)stuff);
  982.         if (fmtStatus != FMT_OK) {
  983.         printf ("Format of VMELINK_WRITE_REG failed, 0x%x\n",
  984.             fmtStatus);
  985.         return GEN_INVALID_ARG;
  986.         }
  987.         status = Mach_Probe (sizeof (stuff[1]), (Address)&(stuff[1]),
  988.                  (Address)regPtr + stuff[0]);
  989.     }
  990.     break;
  991.       case IOC_VMELINK_READ_REG:
  992.     {
  993.         unsigned char stuff[2];
  994.  
  995.         inSize = ioctlPtr->inBufSize;
  996.         outSize = sizeof (stuff);
  997.         fmtStatus = Fmt_Convert ("b2", ioctlPtr->format, &inSize,
  998.                      (Address)ioctlPtr->inBuffer, mach_Format,
  999.                      &outSize, (Address)stuff);
  1000.         if (fmtStatus != FMT_OK) {
  1001.         printf ("Format of VMELINK_READ_REG failed, 0x%x\n",fmtStatus);
  1002.         return GEN_INVALID_ARG;
  1003.         }
  1004.         status = Mach_Probe (sizeof (stuff[1]), (Address)regPtr + stuff[0],
  1005.                  (Address)&(stuff[1]));
  1006.         inSize = sizeof (stuff);
  1007.         outSize = ioctlPtr->outBufSize;
  1008.         fmtStatus = Fmt_Convert ("b2", mach_Format, &inSize,(Address)stuff,
  1009.                      ioctlPtr->format, &outSize,
  1010.                      (Address)ioctlPtr->outBuffer);
  1011.         if (fmtStatus != FMT_OK) {
  1012.         printf ("Format of VMELINK_READ_REG failed, 0x%x\n",fmtStatus);
  1013.         return GEN_INVALID_ARG;
  1014.         }
  1015.     }
  1016.     break;
  1017.  
  1018.       case IOC_VMELINK_PING_REMOTE:
  1019.     /*
  1020.      * Do nothing here; the null call will tell whether the remote
  1021.      * board has been turned on or not.
  1022.      */
  1023.     break;
  1024.       case IOC_LOCK:
  1025.       case IOC_UNLOCK:
  1026.     return (GEN_NOT_IMPLEMENTED);
  1027.     break;
  1028.       case IOC_REPOSITION:
  1029.     {
  1030.         Ioc_RepositionArgs pos;
  1031.         unsigned int curAddr;
  1032.         inSize = ioctlPtr->inBufSize;
  1033.         outSize = sizeof (pos);
  1034.         fmtStatus = Fmt_Convert ("ww", ioctlPtr->format, &inSize,
  1035.                      ioctlPtr->inBuffer, mach_Format,
  1036.                      &outSize, (Address)&pos);
  1037.         if (fmtStatus != FMT_OK) {
  1038.         printf ("DevVMElinkIOControl: IOC 0x%x error 0x%x\n",    
  1039.             ioctlPtr->command, fmtStatus);
  1040.         return (GEN_INVALID_ARG);
  1041.         }
  1042.         switch (pos.base) {
  1043.           case IOC_BASE_ZERO:
  1044.         curAddr = 0x0;
  1045.         break;
  1046.           case IOC_BASE_CURRENT:
  1047.         curAddr = linkData->position;
  1048.         break;
  1049.           case IOC_BASE_EOF:
  1050.         curAddr = 0x0;
  1051.         break;
  1052.           default:
  1053.         return (GEN_INVALID_ARG);
  1054.         break;
  1055.         }
  1056.         if (pos.offset < 0) {
  1057.         linkData->position = curAddr - (unsigned int)(-pos.offset);
  1058.         } else {
  1059.         linkData->position = curAddr + (unsigned int)pos.offset;
  1060.         }
  1061.         if (devVMElinkDebug) {
  1062.         printf ("VMElink: new position is 0x%x\n", linkData->position);
  1063.         }
  1064.     }
  1065.     break;
  1066.       case IOC_GET_FLAGS:
  1067.       case IOC_SET_FLAGS:
  1068.       case IOC_SET_BITS:
  1069.       case IOC_CLEAR_BITS:
  1070.     break;
  1071.       default:
  1072.     return (GEN_NOT_IMPLEMENTED);
  1073.     break;
  1074.     }
  1075.  
  1076.     return (status);
  1077. }
  1078.  
  1079. /*
  1080.  *----------------------------------------------------------------------
  1081.  *
  1082.  * DevVMElinkIOControl
  1083.  *
  1084.  *    Perform an IO control on the VME link card set.  These can
  1085.  *    range from a simple remote ping to playing with the card's
  1086.  *    registers such as address modifiers or window selection.
  1087.  *    No attempt is made to coordinate between two processes that
  1088.  *    mess up the same VME link; that may come in a future version.
  1089.  *
  1090.  * Results:
  1091.  *    
  1092.  *
  1093.  * Side effects:
  1094.  *    May map additional VME address space into the kernel.
  1095.  *    Other side effects depending on the ioctl call requested.
  1096.  *
  1097.  *----------------------------------------------------------------------
  1098.  */
  1099. ENTRY ReturnStatus
  1100. DevVMElinkIOControl (devicePtr, ioctlPtr, replyPtr)
  1101. Fs_Device *devicePtr;    /* Information about device. */
  1102. Fs_IOCParam *ioctlPtr;    /* Parameter information (buffer sizes etc.). */
  1103. Fs_IOReply *replyPtr;    /* Place to store result information.*/
  1104. {
  1105.     VMELinkInfo *linkInfo;
  1106.  
  1107.     if (devVMElinkDebug) {
  1108.     printf ("DevVMElinkIOControl: called for unit %d\n", devicePtr->unit);
  1109.     }
  1110.     if ((devicePtr->unit >= DEV_VMELINK_MAX_BOARDS) ||
  1111.     ((linkInfo = VMEInfo[devicePtr->unit]) == NULL)) {
  1112.     return (DEV_INVALID_UNIT);
  1113.     }
  1114.     return (DevVMElinkBlockIOControl(&(linkInfo->handle), ioctlPtr, replyPtr));
  1115. }
  1116.  
  1117. /*
  1118.  *----------------------------------------------------------------------
  1119.  *
  1120.  * DevVMElinkInit
  1121.  *
  1122.  *    Initialize the VME link board (assuming that there is one
  1123.  *    installed).
  1124.  *    
  1125.  *
  1126.  * Results:
  1127.  *    Returns the "device number" of the VME link.
  1128.  *
  1129.  * Side effects:
  1130.  *    May map additional VME address space into the kernel.
  1131.  *
  1132.  *----------------------------------------------------------------------
  1133.  */
  1134. ENTRY
  1135. ClientData
  1136. DevVMElinkInit(cntrlPtr)
  1137.     DevConfigController *cntrlPtr;
  1138. {
  1139.     CtrlRegs *regPtr = (CtrlRegs *)cntrlPtr->address;
  1140.     register VMELinkInfo *linkInfo;
  1141.     char semName[40];
  1142.     int linkNum;
  1143.     ReturnStatus status;
  1144.     DevBlockDeviceHandle *blockHandle;
  1145.  
  1146.     if (!devVMElinkInitted) {
  1147.     int i;
  1148.     for (i = 0; i < DEV_VMELINK_MAX_BOARDS; i++) {
  1149.         VMEInfo[i] = NULL;
  1150.     }
  1151.     devVMElinkInitted = TRUE;
  1152.     }
  1153.  
  1154.     /*
  1155.      * If the VME link board isn't installed or there are too many boards,
  1156.      * just return.
  1157.      */
  1158.     linkNum = cntrlPtr->controllerID;
  1159.     if (linkNum >= DEV_VMELINK_MAX_BOARDS ||
  1160.     (Mach_Probe(sizeof(regPtr->LocalStatus), (char*)&(regPtr->LocalStatus),
  1161.             (char *)&status) != SUCCESS)) {
  1162.     printf ("%s (VMElink #%d) not found.\n", cntrlPtr->name, linkNum);
  1163.     return (DEV_NO_CONTROLLER);
  1164.     }
  1165.     printf ("%s (VMElink #%d) found.\n", cntrlPtr->name, linkNum);
  1166.     linkInfo = VMEInfo[linkNum] = (VMELinkInfo *)malloc (sizeof (VMELinkInfo));
  1167.     linkInfo->unit = linkNum;
  1168.     linkInfo->LocalFlags = 0;
  1169.     linkInfo->RemoteFlags1 = 0;
  1170.     linkInfo->RemoteFlags2 = 0 /*DEV_VMELINK_REMOTE_PAUSE_16*/;
  1171.     linkInfo->regArea = regPtr;
  1172.     linkInfo->dmaRegs = (DmaRegs *)((char *)regPtr + sizeof (CtrlRegs));
  1173.     linkInfo->addrMsb = 0x80000000;
  1174.     linkInfo->state = 0;
  1175.     linkInfo->vectorNumber = cntrlPtr->vectorNumber;
  1176.     linkInfo->minDmaSize = DEV_VMELINK_MIN_DMA_SIZE;
  1177.     linkInfo->position = 0;
  1178.  
  1179.     sprintf (linkInfo->semName, "VME link 0x%x", linkNum);
  1180.     Sync_SemInitDynamic (&(linkInfo->mutex), semName);
  1181.  
  1182.     List_Init (&(linkInfo->reqHdr));
  1183.     linkInfo->numAttached = 0;
  1184.     linkInfo->curReq = NULL;
  1185.     blockHandle = &(linkInfo->handle.blockHandle);
  1186.     linkInfo->handle.linkInfo = linkInfo;
  1187.     linkInfo->handle.magic = 0xfaced;
  1188.     strcpy (linkInfo->name, cntrlPtr->name);
  1189.     blockHandle->blockIOProc = DevVMElinkBlockIO;
  1190.     blockHandle->IOControlProc = DevVMElinkBlockIOControl;
  1191.     blockHandle->releaseProc = DevVMElinkRelease;
  1192.     blockHandle->minTransferUnit = sizeof (int);
  1193.     blockHandle->maxTransferSize = DEV_VMELINK_MAX_TRANSFER_SIZE;
  1194.  
  1195.     /*
  1196.      * Map in a 64K window so we can use the page register to read or
  1197.      * write from any VME address in the remote cage.
  1198.      */
  1199.     if (windowPhysAddr[linkNum] != 0) {
  1200.     linkInfo->smallMap = (Address)VmMach_MapInBigDevice
  1201.         ((void*)windowPhysAddr[linkNum], 0x10000, VMMACH_TYPE_VME32DATA);
  1202.     if (linkInfo->smallMap == NULL) {
  1203.         printf ("DevVMElinkInit: couldn't map window.\n");
  1204.         linkInfo->state |= DEV_VMELINK_STATE_NO_MAP;
  1205.     } else if (((unsigned)windowPhysAddr[linkNum] & 0xff000000) !=
  1206.            0xff000000) {
  1207.         linkInfo->state |= DEV_VMELINK_STATE_VME_A32;
  1208.         linkInfo->curAddrModifier = 0x0d;
  1209.         printf ("%s is A32D32 with window at 0x%x mapped into 0x%x\n",
  1210.             linkInfo->name,windowPhysAddr[linkNum],linkInfo->smallMap);
  1211.     } else {
  1212.         linkInfo->curAddrModifier = 0x3d;
  1213.         printf ("%s is A32D24 with window at 0x%x mapped into 0x%x\n",
  1214.             linkInfo->name,windowPhysAddr[linkNum],linkInfo->smallMap);
  1215.     }
  1216.     } else {
  1217.     linkInfo->state |= DEV_VMELINK_STATE_NO_MAP;
  1218.     }
  1219.  
  1220.     status = DevVMElinkReset (linkInfo, FALSE);
  1221.  
  1222.     return ((ClientData)(linkInfo));
  1223. }
  1224.  
  1225. /*
  1226.  *----------------------------------------------------------------------
  1227.  *
  1228.  * DevVMElinkOpen
  1229.  *
  1230.  *    Open the VME link device.  Since there isn't much to keep
  1231.  *    track of, just return a handle for future operations.  The
  1232.  *    handle is merely the unit number.
  1233.  *    
  1234.  * Results:
  1235.  *    Standard Sprite ReturnStatus.
  1236.  *
  1237.  * Side effects:
  1238.  *    None.
  1239.  *
  1240.  *----------------------------------------------------------------------
  1241.  */
  1242. ENTRY ReturnStatus
  1243. DevVMElinkOpen (devicePtr, useFlags, notifyToken)
  1244.     Fs_Device *devicePtr;
  1245.     int useFlags;
  1246.     Fs_NotifyToken notifyToken;
  1247. {
  1248.     if (devVMElinkDebug) {
  1249.     printf ("DevVMElinkOpen: Trying to open unit %d\n", devicePtr->unit);
  1250.     }
  1251.     
  1252.     if (devicePtr->unit >= DEV_VMELINK_MAX_BOARDS) {
  1253.     return (DEV_INVALID_UNIT);
  1254.     }
  1255.  
  1256.     devicePtr->data = (ClientData)(VMEInfo[devicePtr->unit]);
  1257.  
  1258.     if (devicePtr->data == NULL) {
  1259.     return (DEV_INVALID_UNIT);
  1260.     }
  1261.     if (devVMElinkDebug) {
  1262.     printf ("VMElink: Opened device successfully (unit %d).\n",
  1263.         devicePtr->unit);
  1264.     }
  1265.  
  1266.     return (SUCCESS);
  1267. }
  1268.  
  1269. /*
  1270.  *----------------------------------------------------------------------
  1271.  *
  1272.  * DevVMElinkRead
  1273.  *
  1274.  *    Read some bytes from the remote VME into a buffer provided.
  1275.  *    Since this may require playing with the virtual->physical
  1276.  *    mapping, the virtual memory may get rearranged.
  1277.  *    
  1278.  * Results:
  1279.  *    SUCCESS if read went OK.
  1280.  *
  1281.  * Side effects:
  1282.  *    May change mapping registers used by the VME driver.
  1283.  *
  1284.  *----------------------------------------------------------------------
  1285.  */
  1286.  
  1287. ENTRY ReturnStatus
  1288. DevVMElinkRead (devicePtr, readPtr, replyPtr)
  1289. Fs_Device *devicePtr;
  1290. Fs_IOParam *readPtr;
  1291. Fs_IOReply *replyPtr;
  1292. {
  1293.     DevBlockDeviceRequest blockReq;
  1294.     ReturnStatus retval;
  1295.     VMELinkInfo *linkInfo = (VMELinkInfo *)devicePtr->data;
  1296.     int xferred;
  1297.  
  1298.     if (devVMElinkDebug) {
  1299.     printf ("DevVMElinkRead: reading 0x%x bytes at offset 0x%x\n",
  1300.         readPtr->length, readPtr->offset);
  1301.     }
  1302.     blockReq.operation = FS_READ;
  1303.     blockReq.startAddress = readPtr->offset;
  1304.     blockReq.bufferLen = readPtr->length;
  1305.     blockReq.buffer = readPtr->buffer;
  1306.  
  1307.     retval = Dev_BlockDeviceIOSync
  1308.     ((DevBlockDeviceHandle *)&(linkInfo->handle), &blockReq, &xferred);
  1309.     replyPtr->flags = FS_READABLE | FS_WRITABLE;
  1310.     replyPtr->length = xferred;
  1311.     return (retval);
  1312. }
  1313.  
  1314. /*
  1315.  *----------------------------------------------------------------------
  1316.  *
  1317.  * DevVMElinkWrite
  1318.  *
  1319.  *    Write some bytes from a buffer to the remote VME.
  1320.  *    Since this may require playing with the virtual->physical
  1321.  *    mapping, the virtual memory may get rearranged.
  1322.  *    
  1323.  * Results:
  1324.  *    SUCCESS if write went OK.
  1325.  *
  1326.  * Side effects:
  1327.  *    May change mapping registers used by the VME driver.
  1328.  *
  1329.  *----------------------------------------------------------------------
  1330.  */
  1331. ENTRY ReturnStatus
  1332. DevVMElinkWrite (devicePtr, writePtr, replyPtr)
  1333. Fs_Device *devicePtr;
  1334. Fs_IOParam *writePtr;
  1335. Fs_IOReply *replyPtr;
  1336. {
  1337.     DevBlockDeviceRequest blockReq;
  1338.     ReturnStatus retval;
  1339.     VMELinkInfo *linkInfo = (VMELinkInfo *)devicePtr->data;
  1340.     int xferred;
  1341.  
  1342.     if (devVMElinkDebug) {
  1343.     printf ("DevVMElinkWrite: writing 0x%x bytes at offset 0x%x\n",
  1344.         writePtr->length, writePtr->offset);
  1345.     }
  1346.     blockReq.operation = FS_WRITE;
  1347.     blockReq.startAddress = writePtr->offset;
  1348.     blockReq.bufferLen = writePtr->length;
  1349.     blockReq.buffer = writePtr->buffer;
  1350.  
  1351.     retval = Dev_BlockDeviceIOSync
  1352.     ((DevBlockDeviceHandle *)&(linkInfo->handle), &blockReq, &xferred);
  1353.     replyPtr->flags = FS_READABLE | FS_WRITABLE;
  1354.     replyPtr->length = xferred;
  1355.     return (retval);
  1356. }
  1357.